import { mkdirSync, delDir, writeFileSync } from "./FileHelper.js";
import { getMergeConfig } from "./mergeConfig.js";
import { refMap, nameToCaml, findRef, nameToClassName } from "./utils.js";

function Definition(_className, data) {
  if(_className.startsWith('Map')) {
    this.isMap = true
    this.noRef = true
    this.mapClassName = nameToClassName(_className)
  }
  this.originClassName = _className
  this.className = nameToCaml(_className)
  this.data = data;
  this.refs = []
  this.refName = `${this.refNamePrefix}${_className}`;
  this.properties = data.properties
  this.findRef = function(ref) {
    var _ref = findRef(ref)
    if(!_ref) return null
    return _ref
  }
  if(!this.noRef) {
    Object.keys(data.properties || {}).forEach((propertyName) => {
      var property = data.properties[propertyName];
      if(property["$ref"]) {
        this.refs.push(property["$ref"])
      }
      if(property.type === "array" && property.items.$ref) {
        this.refs.push(property.items.$ref)
      }
      if(property.allOf) {
        property.allOf.forEach(item => {
          if(item.$ref) {
            this.refs.push(item.$ref)
          }
        })
      }
    })
    this.refs = Array.from(new Set(this.refs))
  }
}

Definition.prototype.refNamePrefix = '#/definitions/'

const _Definition = Definition;
export { _Definition as Definition };

function genDefinitions() {
  var mergeConfig = getMergeConfig()
  var refs = [];
  var definitions = []
  if(mergeConfig.isV3()) {
    Definition.prototype.refNamePrefix = '#/components/schemas/'
  }
  var configDefinitions = mergeConfig.getDefinitions()
  Object.keys(configDefinitions).forEach((_className)=> {
    var definition = new Definition(_className, configDefinitions[_className])
    if(definition.refName) 
      refMap[definition.refName] = definition;
    refs = refs.concat(definition.refs)
    definitions.push(definition);
  })

  mkdirSync(mergeConfig.DIR_CONTROLLERS)
  delDir(mergeConfig.DIR_DEFINITIONS)
  mkdirSync(mergeConfig.DIR_DEFINITIONS)

  writeFileSync(`${mergeConfig.DIR_DEFINITIONS}/Definition.${mergeConfig.DEFINITION_FILE_EXT}`, mergeConfig.DEFINITION_INTERFACE_DEFINE);

  definitions.forEach(item=> {
    if(item.isMap) return
    var definition = item;
    var className = definition.className;
    var defineFilePath = `${mergeConfig.DIR_DEFINITIONS}/${className}.${mergeConfig.DEFINITION_FILE_EXT}`;
    var content = mergeConfig.definitionClassTmpl(
      className,
      mergeConfig.definitionClassRefsTmpl(
        definition.refs.map(ref=> definition.findRef(ref)).filter(item=> !!item && item.className != className).map(item => item.className)
      ),
      mergeConfig.definitionPropertiesTmpl(
        definition
      )
    )
    writeFileSync(defineFilePath, content)
  })
}

const _genDefinitions = genDefinitions;
export { _genDefinitions as genDefinitions };
